function OSGBTileset() {

	THREE.Group.call( this );

	this.type = 'OSGBTileset';

	this.rootPath = "";
	this.referenceCenter = new THREE.Vector3();
	this.rootGeometricError = 1.0;

	this.rootNode = new OSGBGroupNode();
	this.requestTasks = [];
	this.processTasks = [];
	this.loadingTasks = {};

	this.updateNodes = [];
	this.renderModels = [];
	this.deleteModels = [];

	this.url = "";
	this.parser = new OSGBParser(this);

	this.workers = [];
	this.maxActiveTask = 1;

	this.model = null;
}

function handleMeshMessage(worker, event) {
	worker.activeTask--;
	var message = event.data.result;
	var owner = worker.owner;
	owner.handleMesh(message, event.data.buffer);
}

OSGBTileset.prototype = Object.assign( Object.create( THREE.Group.prototype ), {

	constructor: OSGBTileset,

	isGroup: true,

	setTileset: function ( url,isjson ) {
		this.url = url;

		for (var i = 0; i < 4; i++) {
			var worker = new Worker('./threebox/osgb/osgbworker.js');
			worker.owner = this;
			worker.index = i;
			worker.activeTask = 0;
			worker.onmessage = function (event) {
				handleMeshMessage(this, event);
			}
			this.workers.push(worker);
		}

		//this.parser.load("./osgb/Production_OSGB15/Data/Tile_+452_+1356/Tile_+452_+1356.mesh", this.update);
	
		if(isjson){
			this.refresh2();
		}
		else{
			this.refresh();
		}
		

		return this;
	},

	loaded: function (parser) {
		for (var i = 0; i < parser.meshDatas.length; i++) {
			this.model = new OSGBModel(this, parser.meshNames[i], parser.meshDatas[i], parser.textureDatas[i], parser.lodRanges[i], parser.rangeDatas[i]);
			this.model.doCreate();
			this.add(this.model);
		}
	},

	dispose: function () {
		for (var i = 0; i < this.rootNode.getChildrenCount(); ++i) {
			var childNode = this.rootNode.getChild(i);
			if (childNode != null) {
				this.rootNode.releaseChild(childNode, this);
			}
		}
		this.rootNode.removeAllChild();
		this.rootNode.setName("");

		this.deleteRenderables();

		this.processTasks.length = 0;
		this.updateNodes.length = 0;
		this.renderModels.length = 0;
	},

	update: function () {
		this.findVisibleObjects(this.camera);
	},

	findVisibleObjects: function (camera) {

		if (this.model != null) {
			var boundingBox = this.model.getWorldBoundingBox();
			if (camera.intersectsBox(boundingBox)) {
				var k = 0;
			} else {
				var k = 0;
			}
		}

		for (var i = 0; i < this.renderModels.length; i++) {
			var renderModel = this.renderModels[i];
			if (renderModel != null) {
				renderModel.setActive(false);
			}
		}
		this.renderModels.length = 0;

		this.deleteRenderables();
		this.updateNodesEx(camera);

		var nChildrenCount = this.rootNode.getChildrenCount();
		for (var i = 0; i < nChildrenCount; i++) {
			var node = this.rootNode.getChild(i);
			if (node != null) {
				node.traverse(camera, this);
			}
		}

		for (var i = 0; i < this.renderModels.length; i++) {
			var renderModel = this.renderModels[i];
			if (renderModel != null) {
				renderModel.setActive(true);
			}
		}

		if (true) {
			if (this.requestTasks.length > 0) {
				this.requestTasks.sort (function(a, b){
					return a.name.localeCompare(b.name);
				})
			}
			for (var i = 0; i < this.requestTasks.length; i++) {
				this.processTasks.push(this.requestTasks[i]);
			}
			this.requestTasks.length = 0;

			for (var j = this.processTasks.length - 1; j >= 0; j--) {
				var task = this.processTasks[j];
				var parent = task.parent;
				if ((parent.getParent() != null && parent.getName() == task.name) || parent == this.rootNode) {
					var k = 0;
				} else {
					task = null;
					this.processTasks.splice(j, 1);
				}
			}

			this.process();
		}
	},

	apply: function (camera, model) {
		this.renderModels.push(model);
	},

	requestTask: function (name, key, parent) {
		var boundingBox = parent.getWorldBoundingBox();
		var c1 = new THREE.Vector3(0,0,0);
		var position = boundingBox.getCenter(c1);

		var task = new OSGBLodTask();
		task.name = name;
		task.key = key;
		task.parent = parent;
		task.position = position;
		this.requestTasks.push(task);
	},

	deleteNode: function (node) {
		if (node.isGeoNode()) {
			var geoNode = node;
			if (geoNode != null) {
				var model = geoNode.getModel();
				if (model != null) {
					this.deleteModels.push(model);
					geoNode.setModel(null);
				}
			}
		}
	},

	getRootNode: function () {
		return this.rootNode;
	},

	getRootGeometricError: function () {
		return this.rootGeometricError;
	},

	refresh: function () {
		var result = false;
		if (this.rootNode.getName().length == 0) {
			this.rootNode.setName("RootNode");

			var rootNames = [];
			//rootNames.push("Tile_+452_+1356");
			//rootNames.push("Tile_+452_+1357");
			//rootNames.push("Tile_+452_+1358");
			//rootNames.push("Tile_+452_+1359");

			var xmlHttp = new window.XMLHttpRequest();
			xmlHttp.open("GET","./osgb/Production_OSGB15/Data/Production_OSGB15.tmc",false);
			xmlHttp.send(null);
			var parser = new DOMParser();
			var xmlDoc = parser.parseFromString(xmlHttp.responseText,"text/xml");
			var nodes = xmlDoc.children[0].children[0].children[6].children;
			for (var i = 0; i < nodes.length; i++) {
				var rootName = nodes[i].children[0].textContent;
				rootNames.push(rootName);
			}

			for (var i = 0; i < rootNames.length; i++) {
				var rootName = rootNames[i];
				var strKey = rootName + "/" + rootName;
				this.requestTask(rootName, strKey, this.rootNode);
			}

			result = true;
		}
		return result;
	},
	refresh2: function () {
		
		var result = false;
		
		if (this.rootNode.getName().length == 0) {
			this.rootNode.setName("RootNode");

			var rootNames = [];
		
			var xmlHttp = new window.XMLHttpRequest();
			xmlHttp.open("GET",this.url,false);
			xmlHttp.send(null);
			
			var json = JSON.parse(xmlHttp.responseText);
			
			this.url = json.url;

			var nodes =json.nodes;

			for (var i = 0; i < nodes.length; i++) {
				var rootName = nodes[i];
				rootNames.push(rootName);
			}

			for (var i = 0; i < rootNames.length; i++) {
				var rootName = rootNames[i];
				var strKey = rootName + "/" + rootName;
				this.requestTask(rootName, strKey, this.rootNode);
			}

			result = true;
		}
		return result;
	},

	process: function () {
		var lodTask = this.getTask();
		while (lodTask != null) {
			var parent = lodTask.parent;
			if ((parent.getParent() != null && parent.getName() == lodTask.name) || parent == this.rootNode) {
				if (!(lodTask.key in this.loadingTasks)) {
					var message = {
						name: lodTask.name,
						fun: "processMesh",
						url: this.url,
						key: lodTask.key,
					};
					var index = Math.floor(Math.random()*(3-0+1)+0);;
					this.workers[index].postMessage(message);
					this.workers[index].activeTask++;

					this.loadingTasks[lodTask.key] = lodTask;
				}
			}
			lodTask = this.getTask();
		}
		return true;
	},

	handleMesh: function (message, buffers) {
		var lodTask = this.loadingTasks[message.key];
		if (lodTask != null && message.layouts != null) {
			var parser = new OSGBParser();
			parser.fromTransferableObjects(message.layouts, buffers);
			for (var i = 0; i < parser.meshDatas.length; i++) {
				var model = new OSGBModel(this, parser.meshNames[i], parser.meshDatas[i], parser.textureDatas[i], parser.lodRanges[i], parser.rangeDatas[i]);
				lodTask.models.push(model);
			}
			if (lodTask.models.length > 0) {
				this.updateNodes.push(lodTask);
			}
		}
		delete this.loadingTasks[message.key];
	},

	updateNodesEx: function (camera) {
		var updateNodes = [];
		for (var i = 0; i < this.updateNodes.length; i++){
			updateNodes.push(this.updateNodes[i]);
		}
		this.updateNodes.length = 0;

		for (var j = 0; j < updateNodes.length; j++){
			var task = updateNodes[j];
			if (task != null) {
				var models = task.models;
				var parent = task.parent;
				if ((parent.getParent() != null && parent.getName() == task.name) || parent == this.rootNode) {
					var root = parent.getRoot();
					parent.setState(OSGBNodeState.Loaded);

					if (models.length == 1) {
						var model = models[0];
						model.parent = this;
						model.doCreate();
						model.setActive(false);

						if (model.lodRanges.length > 0) {
							var lodNode = new OSGBLodNode();
							if (root == null) {
								root = lodNode;
							}
							lodNode.setRoot(root);
							lodNode.setName(task.name);
							lodNode.setParent(parent);
							lodNode.setModel(model);
							parent.addChild(lodNode);

							var geoNode = new OSGBGeoNode();
							geoNode.setName(task.name);
							geoNode.setParent(lodNode);
							geoNode.setModel(model);
							lodNode.addChild(geoNode);
						} else {
							var geoNode = new OSGBGeoNode();
							geoNode.setName(task.name);
							geoNode.setParent(parent);
							geoNode.setModel(model);
							parent.addChild(geoNode);
						}
					}
					else
					{
						var groupNode = new OSGBGroupNode();
						if (root == null) {
							root = groupNode;
						}

						groupNode.setName(task.name);
						groupNode.setParent(parent);
						groupNode.setRoot(root);
						groupNode.setState(OSGBNodeState.Loaded);
						for (var i = 0; i < models.length; i++){
							var model = models[i];
							model.parent = this;
							model.doCreate();
							model.setActive(false);

							var lodNode = new OSGBLodNode();
							lodNode.setName(task.name);
							lodNode.setParent(groupNode);
							lodNode.setRoot(root);
							lodNode.setModel(model);
							groupNode.addChild(lodNode);

							var geoNode = new OSGBGeoNode();
							geoNode.setName(task.name);
							geoNode.setParent(lodNode);
							geoNode.setModel(model);
							lodNode.addChild(geoNode);
						}
						parent.addChild(groupNode);
					}
				} else {
					for (var i = 0; i < models.length; i++) {
						this.deleteModels.push(models[i]);
					}
				}
				task.models.length = 0;
			}
		}

		return 0;
	},

	getTask: function () {
		var task = null;
		if (this.processTasks.length > 0) {
			task = this.processTasks[0];
			this.processTasks.splice(0, 1);
		}
		return task;
	},

	loadRenderModels: function (strKey, referenceCenter) {
		var renderModels = [];
		var filePath = this.rootPath + strKey + ".osgb";
		var fileParser = new OSGBParser();
		if (fileParser.load(filePath, referenceCenter)) {
			for (var i = 0; i < fileParser.meshDatas.length; i++) {
				var renderModel = new OSGBModel(fileParser.meshNames[i], fileParser.meshDatas[i], fileParser.textureDatas[i], fileParser.lodRanges[i], fileParser.rangeDatas[i]);
				renderModels.push(renderModel);
			}
		}
		return renderModels;
	},

	deleteRenderables: function (strKey, referenceCenter) {
		for (var i = 0; i < this.deleteModels.length; i++){
			var renderModel = this.deleteModels[i];
			if (renderModel != null) {
				renderModel.setActive(false);
				renderModel.doDestroy();
			}
		}
		this.deleteModels.length = 0;
	},

} );

